import Vue from 'vue'
import {
    isString,
    isObject
} from './type-check'

const hasOwnProperty = Object.prototype.hasOwnProperty

export function noop() {}

export function hasOwn(obj, key) {
    return hasOwnProperty.call(obj, key)
}

function extend(to, _from) {
    for (const key in _from) {
        to[key] = _from[key]
    }
    return to
}

/**
 * 转成对象
 * @param {*} arr 
 * @returns 
 */
export function toObject(arr) {
    var res = {}
    for (let i = 0; i < arr.length; i++) {
        if (arr[i]) {
            extend(res, arr[i])
        }
    }
    return res
}

/**
 * 
 * @param {*} object 
 * @param {*} prop 
 * @returns 
 */
export const getValueByPath = function (object, prop) {
    prop = prop || ''
    const paths = prop.split('.')
    let current = object
    let result = null
    for (let i = 0, j = paths.length; i < j; i++) {
        const path = paths[i]
        if (!current) break

        if (i === j - 1) {
            result = current[path]
            break
        }
        current = current[path]
    }
    return result
}

/**
 * 
 * @param {*} obj 
 * @param {*} path 
 * @param {*} strict 
 * @returns 
 */
export function getPropByPath(obj, path, strict) {
    let tempObj = obj
    path = path.replace(/\[(\w+)\]/g, '.$1')
    path = path.replace(/^\./, '')

    const keyArr = path.split('.')
    let i = 0
    for (let len = keyArr.length; i < len - 1; ++i) {
        if (!tempObj && !strict) break
        const key = keyArr[i]
        if (key in tempObj) {
            tempObj = tempObj[key]
        } else {
            if (strict) {
                throw new Error('please transfer a valid prop path to form item!')
            }
            break
        }
    }
    return {
        o: tempObj,
        k: keyArr[i],
        v: tempObj ? tempObj[keyArr[i]] : null
    }
}


/**
 * 
 * @param {*} a 
 * @param {*} b 
 * @returns 
 */
export const valueEquals = (a, b) => {
    // see: https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
    if (a === b) return true
    if (!(a instanceof Array)) return false
    if (!(b instanceof Array)) return false
    if (a.length !== b.length) return false
    for (let i = 0; i !== a.length; ++i) {
        if (a[i] !== b[i]) return false
    }
    return true
}


/**
 * 将值强制到数组
 * @param {*} val 
 * @returns 
 */
export const coerceTruthyValueToArray = function (val) {
    if (Array.isArray(val)) {
        return val
    } else if (val) {
        return [val]
    } else {
        return []
    }
}


/**
 * 首字母大写
 * @param {*} str 
 * @returns 
 */
export const capitalize = function (str) {
    if (!isString(str)) return str
    return str.charAt(0).toUpperCase() + str.slice(1)
}


/**
 * 数据是否一样
 * @param {*} a 
 * @param {*} b 
 * @returns 
 */
export const looseEqual = function (a, b) {
    const isObjectA = isObject(a)
    const isObjectB = isObject(b)
    if (isObjectA && isObjectB) {
        return JSON.stringify(a) === JSON.stringify(b)
    } else if (!isObjectA && !isObjectB) {
        return String(a) === String(b)
    } else {
        return false
    }
}

/**
 * 两个数组是否一样
 * @param {*} arrayA 
 * @param {*} arrayB 
 * @returns 
 */
export const arrayEquals = function (arrayA, arrayB) {
    arrayA = arrayA || []
    arrayB = arrayB || []

    if (arrayA.length !== arrayB.length) {
        return false
    }

    for (let i = 0; i < arrayA.length; i++) {
        if (!looseEqual(arrayA[i], arrayB[i])) {
            return false
        }
    }

    return true
}

/**
 * 数据是否对等
 * @param {*} value1 
 * @param {*} value2 
 * @returns 
 */
export const isEqual = function (value1, value2) {
    if (Array.isArray(value1) && Array.isArray(value2)) {
        return arrayEquals(value1, value2)
    }
    return looseEqual(value1, value2)
}

/**
 * 数据是否为空
 * @param {*} val 
 * @returns 
 */
export const isEmpty = function (val) {
    // null or undefined
    if (val == null || val == undefined) return true

    if (typeof val === 'boolean') return false

    if (typeof val === 'number') return !val

    if (val instanceof Error) return val.message === ''

    switch (Object.prototype.toString.call(val)) {
        // String or Array
        case '[object String]':
        case '[object Array]':
            return !val.length

        // Map or Set or File
        case '[object File]':
        case '[object Map]':
        case '[object Set]': {
            return !val.size
        }

        // Plain Object
        case '[object Object]': {
            return !Object.keys(val).length
        }
    }

    return false
}


export function objToArray(obj) {
    if (Array.isArray(obj)) {
        return obj
    }
    return isEmpty(obj) ? [] : [obj]
}